/*
 * Copyright 2006-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package asphalt2.util
{
	import flash.utils.describeType;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	
	import mx.collections.ArrayCollection;
	import mx.utils.ObjectUtil;
	/**
	 * BeanUtil
	 * @author c9katayama
	 */	
	public class BeanUtil {
		/**
		 * フィールドをコピーします。
		 */
		public static function copyField(fieldName:String,srcObject:Object,targetObject:Object):void{
			if(srcObject[fieldName]==null){
				targetObject[fieldName] = null;
			}else{
				var srcField:* = srcObject[fieldName];
				if(!isSimple(srcField)){
					targetObject[fieldName] = copyObject(srcField);
				}else{
					targetObject[fieldName] = srcField;
				}
			}
		}
		/**
		 * プロパティをコピーします。
		 * @param srcObjec コピー元のオブジェクト
		 * @param targetObjec コピー先のオブジェクト
		 * @param strict コピー元になくコピー先にあるプロパティを消すかどうか　
		 * 　　　　　　　デフォルトはfalse
		 */
		public static function copyProperty(srcObject:Object,targetObject:Object):void{
			var fqcn:String = getQualifiedClassName(srcObject);
			if(fqcn == "Object"){
				for(var key:String in srcObject){
					targetObject[key] = srcObject[key];
				}
			}else{
				var accessors:XMLList = describeType(srcObject).accessor;
				if(accessors != null){
					for each(var accessor:* in accessors){
						copyField(accessor.@name,srcObject,targetObject);
					}
				}
			}
		}
		/**
		 * オブジェクトをコピーします。
		 * @param srcObjec コピー元のオブジェクト
		 */
		public static function copyObject(srcObject:*):*{
			if(srcObject == null){
				return null;
			}
			if(srcObject is Array){
				return copyArray(srcObject);
			}else if(srcObject is ArrayCollection){
				return copyArrayCollection(srcObject);
			}else{
				var target:* = newInstanceByInstance(srcObject);		
				copyProperty(srcObject,target);
				return target;
			}		
		}
		/**
		 * ArrayCollectionをコピーします。
		 * コピー元がnullの場合、新しいArrayCollectionを返します。
		 * @param src_array コピー元のArrayCollection
		 * @param target_array コピー先のArrayCollection
		 */
		public static function copyArrayCollection(src_array:ArrayCollection):ArrayCollection{
			if(src_array==null){
				return null;
			}
			var target_array:ArrayCollection = new ArrayCollection();
			for(var i:int = 0;i < src_array.length;i++){
				var obj:* = src_array[i];
				if(!isSimple(obj)){
					target_array.addItem(copyObject(obj));
				}else{
					target_array.addItem(obj);
				}
			}
			return target_array;
		}		
		/**
		 * 配列をコピーします。
		 * コピー元がnullの場合、新しい配列を返します。
		 * @param src_array コピー元の配列
		 * @param target_array コピー先の配列
		 */
		public static function copyArray(src_array:Array):Array{
			if(src_array==null){
				return null;
			}
			var target_array:Array = new Array();
			for(var i:int = 0;i < src_array.length;i++){
				var obj:* = src_array[i];
				if(!isSimple(obj)){
					target_array.push(copyObject(obj));
				}else{
					target_array.push(obj);
				}
			}
			return target_array;
		}	
		/**
		 * 2つのオブジェクトを比較します。
		 * @param srcObject 比較元のオブジェクト
		 * @param srcObject 比較先のオブジェクト
		 * @param ignoreNull nullもしくはundefinedのプロパティを比較対象から外すかどうか　デフォルトはfalse
		 */
		public static function compareObj(srcObject:*,targetObject:*,ignoreNull:Boolean=false):Boolean{
			if(srcObject==null && targetObject == null)
				return true;
			
			if(srcObject==null && targetObject != null)
				return false;
	
			if(srcObject!=null && targetObject == null)
				return false;
				
			if(typeof(srcObject) != typeof(targetObject)){
				return false;
			}
			
			return ObjectUtil.compare(srcObject,targetObject) ==0 ? true : false;
		}
		public static function compareArray(src_array:Array,target_array:Array):Boolean{
			
			if(src_array==null && target_array == null)
				return true;
			
			if(src_array==null && target_array != null)
				return false;
	
			if(src_array!=null && target_array == null)
				return false;
			
			if(!(src_array is Array) || !(target_array is Array)){
				return false;
			}
			return ObjectUtil.compare(src_array,target_array) ==0 ? true : false;
		}
		private static function isSimple(value:*):Boolean{
	    	if(value===null||value===undefined){
	    		return true;
	    	}
	        var type:String = typeof(value);
	        switch (type)
	        {
	            case "number":
	            case "string":
	            case "boolean":
	            {
	                return true;
	            }
	        }
	        return false;
		}
		public static function newInstanceByInstance(baseObject:Object):*{
			var fqcn:String = getQualifiedClassName(baseObject);
			return newInstance(fqcn);
		}
		public static function newInstance(fqcn:String):*{
			var c:Class = getDefinitionByName(fqcn) as Class;
			var instance:Object = new c();
			return instance;		
		}
	}
}